package mutex

import (
	"fmt"
	"sync"
	"time"
)

type objM struct {
	Name string
	mux  sync.Mutex
}

var innerOb objM

//如果返回的不是指针类型是会造成2个对象的锁不一致。
func GetMuxObj() *objM {
	return &innerOb
}
func init() {
	innerOb = objM{Name: "default"}
}

//包含锁的结构体，如果用值类型方法会导致锁失效
func (m *objM) Read() {
	m.mux.Lock()
	defer m.mux.Unlock()

	fmt.Println("读锁获取成功")
	fmt.Println(m.Name)
}

func (m *objM) Write(name string) {
	m.mux.Lock()
	defer m.mux.Unlock()
	m.Name = name
	fmt.Println("写入成功")
	time.Sleep(time.Second * 5)
	fmt.Println("写锁释放成功")
}

func MutexTest() {
	var mutex sync.Mutex
	mutex.Lock()
	for i := 0; i < 5; i++ {
		go func(x int) {
			mutex.Lock()
			//defer mutex.Unlock()
			fmt.Println("this is a test", x)
		}(i)
	}
	fmt.Println("this run")
	time.Sleep(time.Second * 3)
	mutex.Unlock()
}

type Test struct {
	Mux  sync.Mutex
	Name string
}
type Test1 struct {
	Mux  *sync.Mutex
	Name string
}

//结构体的值传递一样会导致锁失效
func StructValuePassMutex(t Test) {
	//t.Mux.Lock()
	fmt.Printf("值类型结构体锁地址：%p\n", &t.Mux)
}

//个人理解，结构体中的锁如果是指针，会根据地址判断锁是否会失效
func StructPtrPassMutex(t Test1) {
	fmt.Println("等待锁", time.Now())
	t.Mux.Lock()
	fmt.Println("获取到锁", time.Now())
	defer t.Mux.Unlock()
	fmt.Printf("指针对象的锁地址及锁指向的地址：%p,%p\n", &t.Mux, t.Mux)
}

func ValuePassMutex() {
	mux := sync.Mutex{}
	fmt.Printf("自己的地址%p\n", &mux)
	mux.Lock()
	defer mux.Unlock() //重复关闭互持锁引发panic
	fmt.Println("start")
	transmitMutex1(mux)
	transmitMutex2(&mux)
	time.Sleep(time.Second * 5)

}

func transmitMutex1(m sync.Mutex) {
	/*	m.Lock()
		defer m.Unlock()*/

	fmt.Printf("值传递：%p\n", &m)
}
func transmitMutex2(m *sync.Mutex) {
	m.Unlock()
	fmt.Printf("地址传递：%p\n", m)
}
